package in.muton.edushare.documentModel.excel;


import in.muton.edushare.documentModel.excel.StylePalette.CELL_STYLE;

import java.util.ArrayList;
import java.util.List;

import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;

/**
 * <p>
 * Most basic form of a table, can be positioned flexibly.
 * keeps handle of boundary, current cursor position, current Row and current Cell
 * </p>
 * <p>
 * The implementing classes are left to decorate the cells and rows or to add extra elements 
 * like table with fixed header or table with boundary etc.
 * </p>
 * @author naishe
 *
 */
public abstract class AbsTable {

	public static enum TABLE_POSITION{
		ABSOLUTE_ROW,
		ABSOLUTE_COLUMN,
		ABSOLUTE_BOTH,
		RELATIVE
	};
	protected SimpleExcelDocument doc;
	protected List<Row> rows;
	private HSSFRow currentRow;
	private Cell currentCell;
	private int currentRowNumber;
	private int currentColNumber;
	

	//The following four variables define boundary of the table
	private int startRow;//Top-left Y
	private int startColumn;//Top-left X
	private int endRow;//Bottom-right Y
	private int endColumn;//X of longest row in the table  
	private TABLE_POSITION position;
	
	public AbsTable(SimpleExcelDocument doc, int startRow, int startColumn, TABLE_POSITION position) {
		this.doc = doc;
		this.position = position;
		setAbsolutePosition(startRow, startColumn);
		this.currentRowNumber = this.startRow-1;
		this.currentColNumber = this.startColumn-1;
		this.rows = new ArrayList<Row>();
		doc.append(this);
		
	}
	
	/**
	 * Creates a relative table, appending just below previous table, sticking to left border
	 * @param SimpleExcelDocument
	 */
	public AbsTable(SimpleExcelDocument doc){
		this(doc, 0, 0, TABLE_POSITION.ABSOLUTE_COLUMN);
	}
	
	/**
	 * positions table absolutely in presence of other tables
	 * @param startRow
	 * @param startColumn
	 */
	private void setAbsolutePosition(int startRow, int startColumn) {
		//TODO: set simple positioning for now! Need to refine this logic
		AbsTable prevTable = null;
		if(doc.getTables()!=null && doc.getTables().size()>0)
			prevTable = doc.getTables().get(doc.getTables().size()-1);
		
		//In relative scheme cases, we need to advance relative cursor one step 
		//before adding the relative position of top-left of new table because the cursor
		//is pointing at right-bottom of previous box!
		if(prevTable==null || this.position == TABLE_POSITION.ABSOLUTE_BOTH){
			this.startRow = startRow;
			this.startColumn = startColumn;
		}else if(this.position==TABLE_POSITION.RELATIVE){
			this.startRow = (prevTable.getEndRow()+1) + startRow;
			this.startColumn = (prevTable.getEndColumn()+1) + startColumn;
		}else if(this.position == TABLE_POSITION.ABSOLUTE_COLUMN){
			this.startRow = (prevTable.getEndRow()+1) + startRow;
			this.startColumn = startColumn;
		}else if(this.position == TABLE_POSITION.ABSOLUTE_ROW){
			this.startRow = startRow;
			this.startColumn = (prevTable.getEndColumn()+1) + startColumn;
		}
	}

	/**
	 * Creates a new row and appends to the table
	 */
	public void nextRow(){
		currentRowNumber++;
		currentColNumber = this.startColumn-1;
		endRow = currentRowNumber;
		rows.add(this.currentRow = doc.getSheet().createRow(currentRowNumber));
	}
	
	public AbsTable addCell(boolean data){
		advanceCellByOne();
		currentCell.setCellValue(data);
		return this;
	}

	public AbsTable addCell(String data){
		advanceCellByOne();
		String lines = "";
		List<String> l = StringUtils.breakIntoListOfLines(data, 30);
		for(int i=0; i<l.size(); i++){
			if(i>0)
				lines = lines+"\n";
			lines = lines + l.get(i);
		}
		if(currentRow.getHeightInPoints()<l.size()*doc.getSheet().getDefaultRowHeightInPoints())
			currentRow.setHeightInPoints(l.size()*doc.getSheet().getDefaultRowHeightInPoints());
		currentCell.setCellValue(lines);
		return this;
	}
	
	public AbsTable addCell(double data){
		advanceCellByOne();
		currentCell.setCellValue(data);
		return this;
	}
	
	/**
	 * Advances cell by one and checks if this cell define right boundary of the table
	 */
	private void advanceCellByOne() {
		currentColNumber++;
		this.currentCell = createNextCell(currentColNumber);
		if(currentColNumber > this.endColumn)
			endColumn = currentColNumber;
	}

	/**
	 * The implementing class will set style border etc
	 * @param currentColNumber
	 * @return
	 */
	protected abstract Cell createNextCell(int currentColNumber);

	public AbsTable setStyle(CELL_STYLE style) {
		currentCell.setCellStyle(doc.getStylePalette().getStyle(style));
		return this;
	}
	
	//getters
	public int getCurrentRowNumber() {
		return currentRowNumber;
	}

	public int getStartRow() {
		return startRow;
	}

	public int getStartColumn() {
		return startColumn;
	}

	public int getEndRow() {
		return endRow;
	}

	public int getEndColumn() {
		return endColumn;
	}

	public TABLE_POSITION getPosition() {
		return position;
	}
	
	public HSSFRow getCurrentRow() {
		return currentRow;
	}
	
	public Cell getCurrentCell(){
		return currentCell;
	}
		
}
